﻿using System;
using System.Text;
using AppsGenerator.Generators;
using CommonLogging;
using AppsGenerator.Models;
using DBBuilder.DBDataStructure;
using System.Xml.Serialization;
using System.IO;
using System.Xml;

namespace AppsGenerator.WebGenerators.WebModelGenerator
{
    /// <summary>
    /// The base class for generating partials of model
    /// </summary>
    public abstract class PartialModelGenerator : BaseGenerator
    {
        #region Fields

        /// <summary>
        /// The instance of _classComponents, this object will be updated when deserialization pattern file
        /// </summary>
        private ClassComponents _classComponents;

        /// <summary>
        /// The logger instance
        /// </summary>
        private readonly ILogger Logger = LoggerManager.GetLogger(typeof(PartialModelUserGenerator).Name);  

        #endregion

        #region Methods

        /// <summary>
        /// Deserialize pattern file
        /// </summary>
        public void DeserializeTemplate()
        {
            var patternFile = Path.Combine(this.GetAppPath(), "Templates", "WebTemplates", this.XMLTemplate);

            using (XmlTextReader xreader = new XmlTextReader(patternFile))
            {
                xreader.Namespaces = false;
                try
                {
                    var x = new XmlSerializer(typeof(ClassComponents));
                    this._classComponents = x.Deserialize(xreader) as ClassComponents;
                }
                catch (Exception ex)
                {
                    throw new Exception(string.Format("Cannot deserialize UserInfoModelTemplate, UserInfoModelTemplate => {0}", ex.Message));
                }
            }
        }

        /// <summary>
        /// Method to generate script components
        /// </summary>
        /// <param name="tbl"></param>
        public void GenerateContents(Table tbl)
        {
            this.Logger.InfoFormat("Generate Model[{0}] --> Start", tbl.Name);
            Console.WriteLine("Generate Model[{0}] --> Start", tbl.Name);

            try
            {
                var contents = new StringBuilder(BaseConsts.MAX_BYTES);

                // Generating Using region
                contents.AppendLine(this._classComponents.UsingPart);
                contents.AppendLine(string.Empty);

                // Generating Class region
                contents.AppendLine(string.Format("namespace {0}.Models", this.GlobalNameSpace));
                contents.Append("{");
                contents.AppendLine(this._classComponents.ClassPart.Comment);
                contents.Append(BaseConsts.TAB1).AppendLine(string.Format("public class Custom{0}", tbl.Name));
                contents.Append(BaseConsts.TAB1).AppendLine("{");

                // Generating Regions Fields
                contents.Append(this.GenerateRegionFields(tbl));

                contents.Append(BaseConsts.TAB1).AppendLine("}");
                contents.Append("}");
                contents.AppendLine();

                // Save controller contents to a file
                this.SaveFile(contents.ToString().TrimStart(), string.Format("Custom{0}.cs", tbl.Name));
            }
            catch (Exception ex)
            {
                this.Logger.ErrorFormat("GenerateContents Error: {0}", ex.ToString());
                throw new Exception(ex.ToString());
            }
            
            this.Logger.InfoFormat("Generate Model[{0}] <-- End", tbl.Name);
            Console.WriteLine("Generate Model[{0}] <-- End", tbl.Name);
        }

        /// <summary>
        /// The method for generating region fields
        /// </summary>
        /// <param name="tbl">Data source for generating</param>
        /// <returns></returns>
        private string GenerateRegionFields(Table tbl)
        {
            var contents = new StringBuilder(BaseConsts.MAX_BYTES);

            // Generating Regions Fields
            contents.Append(BaseConsts.TAB2).AppendLine("#region Fields");
            contents.Append(BaseConsts.TAB2).AppendLine(string.Empty);

            foreach (Region region in this._classComponents.ClassPart.Regions)
            {
                foreach (Item item in region.Items)
                {
                    contents.AppendLine(item.Content.Replace(BaseConsts.ConstTable, tbl.Name));
                    contents.AppendLine(string.Empty);
                }
            }

            contents.Append(BaseConsts.TAB2).AppendLine("#endregion");

            return contents.ToString();
        }

        #endregion
    }
}
